'/
' MOTEP - Massive Online Text Environment Project
' --------------------------------------------------------------------------------
' MOTEP Server
' 
' Main.bmx
' 
' (c) Anton Berlin. All Rights Reserved.
'/

strict

import bah.raknet

include "Main_h.bmx"
include "..\Shared\Strings.bmx"
include "..\Shared\Keycodes_h.bmx"
include "..\Shared\ADL.bmx"
include "..\Shared\NetUtil.bmx"
include "..\Shared\MessageIdentifiers.bmx"
include "..\Shared\World.bmx"
include "..\Shared\Character.bmx"
include "..\Shared\Console.bmx"
include "CharacterManagement.bmx"
include "Master.bmx"
include "..\Shared\Output.bmx"
include "GUI.bmx"
include "Commands.bmx"

' Set application title
AppTitle = APP_TITLE

' Set the random seed to MilliSeconds
SeedRnd MilliSecs()

' Graphics stuff
Graphics(RES_X, RES_Y)
SetBlend(ALPHABLEND)

' Flush the input
FlushKeys()
FlushMouse()

' Call main loop.
main()
Delay(750)
end



' ==============================================================================
' Main function.
' ==============================================================================
function main()
	' Open the log stream for writing.
	if (FileType(LOG_FILE) = 0) then
		local success:int = CreateFile(LOG_FILE)
		if (not success) RuntimeError("Could not create file ~q" + LOG_FILE + "~q.")
	end if
	logHandle = WriteStream(LOG_FILE)
	if (not logHandle) then
		RuntimeError("Could not load ~q" + LOG_FILE + "~q to memory.")
		return 0
	end if
	
	' Begin the log.
	outLog("Log initiated.")
	outLog(APP_TITLE + " v" + APP_VERSION + " - Startup: " + CurrentTime() + " " + CurrentDate())
	outLog(DOUBLE_DASH_BAR)
	outLog("")
	
	' Initialize the master object.
	Master.Initialize()
	
	' Flush input.
	flushInput()
	
	' Load fonts to memory.
	loadFonts()
	
	' Load the server settings.
	write("Loading settings from ~q" + SERVER_CONFIG + "~q.")
	if (not loadServerSettings()) then
		renderFrame()
		Delay(1000)
		return
	end if
	
	write("Servername set to ~q" + serverName + "~q.")
	
	' Create the server peer.
	serverPeer = TRKRakNetworkFactory.GetRakPeerInterface()
	
	' Startup the network threads.
	local s:TRKSocketDescriptor = TRKSocketDescriptor.CreateSocketDescriptor(serverPort)
	serverPeer.Startup(maxConnections, 30, s)
	serverPeer.SetMaximumIncomingConnections(maxConnections)
	write(APP_TITLE + " v" + APP_VERSION)
	write(DOUBLE_DASH_BAR)
	renderFrame()
	Delay(100)
	
	' Load databases to memory.
	write("Loading databases to memory.")
	renderFrame()
	WorldDatabase.LoadADL("ADL\world.adl")
	CharacterDatabase.LoadADL("ADL\characters.adl")
	
	' Create a TMap of all the characters that are stored on this server.
	write("Creating character map.")
	GlobalCharMap = CreateCharacterMap()
	
	' Connect to master server.
	write("Connecting to master server at ~q" + masterIP + ":" + masterPort + "~q.")
	renderFrame()
	if (not serverPeer.Connect(masterIP, masterPort, "", 1)) then
		write("Could not connect to master server.")
		renderFrame()
		return 0
	end if
	
	' Main loop.
	while (not Master.m_stopEvent and not AppTerminate())
		' Let other applications get CPU power as well.
		Delay(10)
		
		' Main routine.
		Master.Run()
		
		' Check if escaped was pressed - if so, escape the main loop.
		if (GetChar() = KEY_ESCAPE) then
			Master.m_stopEvent = true
			write("Shutting down server.")
			renderFrame()
		end if
	end while
	
	' Terminate session.
	if (serverPeer) then
		serverPeer.Shutdown(peerShutdownTime)
		TRKRakNetworkFactory.DestroyRakPeerInterface(serverPeer)
	end if
	
	' Save databases to disc.
	WorldDatabase.SaveADL("ADL\world.adl")
	CharacterDatabase.LoadADL("ADL\characters.adl")
	
	' End the log.
	outLog("")
	outLog(DOUBLE_DASH_BAR)
	outLog("Log ended: " + CurrentTime() + " " + CurrentDate())
	
	' Close the log stream.
	CloseStream(logHandle)
end function

' Write a line into the log.
function outLog(str:string)
	WriteLine(logHandle, str)
end function

' Clear screen, decide which type of screen to render the frame
' from next, and then render it.
function renderFrame()
	cls ' Clear the screen for the next frame.
	drawFrame_Server()
	flip ' Flip the buffers.
end function

' Load server settings.
function loadServerSettings:int()
	Local fileHandle:TStream = ReadStream(SERVER_CONFIG)
	
	if (not fileHandle) then
		write("Could not load ~q" + SERVER_CONFIG + "~q.")
		return 0
	end if
	
	while (not Eof(fileHandle)) ' Read each line of the config file.
		local data:string = ReadLine(fileHandle)
		local variable:string = str.strip(str.word(0, data, KEY_EQUAL))
		local value:string = str.word(1, data, KEY_EQUAL)
		
		if (Mid(data, 1, 1) = "#") continue
		
		select (lower(variable))
			case "type"
				if (value = "0") then
					serverPort = PVE_SERVER_PORT
				else if (value = "1") then
					serverPort = PVP_SERVER_PORT
				end if
			case "name"
				serverName = value
			case "masterip"
				masterIP = str.strip(str.word(0, value, KEY_COLON))
				masterPort = int(str.strip(str.word(1, value, KEY_COLON)))
		end select
	end while
	
	CloseStream(fileHandle)
	
	if (not serverPort) then
		write("CONFIG ERROR: Invalid server type!")
		return 0
	else if (not masterIP and masterPort) then
		write("CONFIG ERROR: No master-server IP specified!")
		return 0
	else if (masterIP and not masterPort) then
		write("CONFIG ERROR: No master-server port specified!")
		return 0
	else if (not masterIP and not masterPort) then
		write("CONFIG ERROR: No master-server IP or port specified!")
		return 0
	end if
	
	return 1
end function

' Send a message to a client peer.
function sendMessageToClient:byte(targetPeer:TRKSystemAddress, msg:string, packetChannel:int, identifier:string = ID_QUERY)
	if (not serverPeer) return 0
	sendMessageToPeer(serverPeer, identifier + " " + msg, packetChannel, targetPeer)
	return 1
end function

' Send a message to the master server.
function sendMessageToMaster:byte(msg:string, packetChannel:int, identifier:string = ID_QUERY)
	if (not masterAddr) return 0
	if (not serverPeer) return 0
	sendMessageToPeer(serverPeer, identifier + " " + msg, packetChannel, masterAddr)
	return 1
end function
